#pragma once
#include "brpc/server.h"
#include "butil/logging.h"

#include "asr.hpp" //语音识别
#include "file.pb.h"
#include "logger.hpp" //日志
#include "etcd.hpp"   //服务注册
#include <memory>
#include "utils.hpp"

class FileServiceImpl : public lch_im::FileService
{
public:
    FileServiceImpl(const std::string storage_path) :_storage_path(storage_path) {
        umask(0);
        mkdir(_storage_path.c_str(),0775);
        if(_storage_path.back() != '/') {
            _storage_path.push_back('/');
        }
    }
    ~FileServiceImpl() {}

    void GetSingleFile(google::protobuf::RpcController *controller,
                  const lch_im::GetSingleFileReq *request,
                   lch_im::GetSingleFileRsp *response,
                  ::google::protobuf::Closure *done)
    {
        LOG_DEBUG("收到单个文件请求");
        brpc::ClosureGuard rpc_guard(done);
        response->set_request_id(request->request_id());
        // 先取出文件的ID
        std::string f_id = request->file_id();
        std::string filename = _storage_path + f_id;
        // 文件ID就是文件的名字,读取文件
        std::string body;
        bool ret = readFile(filename, body);
        if (ret == false)
        {
            response->set_success(false);
            response->set_errmsg("读取文件失败");
            LOG_ERROR("{}读取文件失败", request->request_id());
            return;
        }

        response->set_success(true);
        response->mutable_file_data()->set_file_id(f_id);
        response->mutable_file_data()->set_file_content(body);
        LOG_DEBUG("单个文件请求完成");
    }

    void GetMultiFile(google::protobuf::RpcController *controller,
                 const lch_im::GetMultiFileReq *request,
                  lch_im::GetMultiFileRsp *response,
                 ::google::protobuf::Closure *done)
    {
        brpc::ClosureGuard rpc_guard(done);
        response->set_request_id(request->request_id());
        for (int i = 0; i < request->file_id_list_size(); i++)
        {
            std::string f_id = request->file_id_list(i);
            std::string filename = _storage_path + f_id;
            std::string body;
            bool ret = readFile(filename, body);
            if (ret == false)
            {
                response->set_success(false);
                response->set_errmsg("读取文件失败");
                LOG_ERROR("{}读取文件失败", request->request_id());
                return;
            }

            lch_im::FileDownloadData data;
            data.set_file_id(f_id);
            data.set_file_content(body);
            response->mutable_file_data()->insert({f_id, data});
        }

        response->set_success(true);
    }

    void PutSingleFile(google::protobuf::RpcController *controller,
                  const lch_im::PutSingleFileReq *request,
                   lch_im::PutSingleFileRsp *response,
                  ::google::protobuf::Closure *done)
    {
        brpc::ClosureGuard rpc_guard(done);
        response->set_request_id(request->request_id());

        std::string f_id = uuid();
        std::string filename = _storage_path + f_id;
        // 取出数据，将数据写入到唯一uuid的文件中
        bool ret = writeFile(filename, request->file_data().file_content());
        if (ret == false)
        {
            response->set_success(false);
            response->set_errmsg("读取文件失败");
            LOG_ERROR("{}写入文件失败", request->request_id());
            return;
        }
        response->set_success(true);
        response->mutable_file_info()->set_file_id(f_id);
        response->mutable_file_info()->set_file_size(request->file_data().file_size());
        response->mutable_file_info()->set_file_name(request->file_data().file_name());
    }

    void PutMultiFile(google::protobuf::RpcController *controller,
                 const lch_im::PutMultiFileReq *request,
                  lch_im::PutMultiFileRsp *response,
                 ::google::protobuf::Closure *done)
    {
        brpc::ClosureGuard rpc_guard(done);
        response->set_request_id(request->request_id());
        for (int i = 0; i < request->file_data_size(); ++i)
        {
            std::string f_id = uuid();
            std::string filename = _storage_path + f_id;
            bool ret = writeFile(filename, request->file_data(i).file_content());
            if (ret == false)
            {
                response->set_success(false);
                response->set_errmsg("读取文件失败");
                LOG_ERROR("{}写入文件失败", request->request_id());
                return;
            }
            response->set_success(true);
            lch_im::FileMessageInfo *info = response->add_file_data();
            info->set_file_id(f_id);
            info->set_file_size(request->file_data(i).file_size());
            info->set_file_name(request->file_data(i).file_name());
        }
        response->set_success(true);
    }

private:
    std::string _storage_path;
};

class FileServer
{
public:
    using ptr = std::shared_ptr<FileServer>;

    FileServer(const Registery::ptr &reg_client, const std::shared_ptr<brpc::Server> &rpc_server)
        : _reg_client(reg_client),
          _rpc_server(rpc_server)
    {
    }

    ~FileServer() {}

    void start()
    {
        _rpc_server->RunUntilAskedToQuit();
    }

private:
    Registery::ptr _reg_client;
    std::shared_ptr<brpc::Server> _rpc_server;
};

class FileServerBuild
{
public:
    void create_reg_object(const std::string &reg_host, const std::string &service_name, const std::string &access_host)
    {
        _reg_client = std::make_shared<Registery>(reg_host);
        _reg_client->registry(service_name, access_host);
    }

    void create_rpc_object(uint16_t port, int32_t timeout, uint8_t num_threads,const std::string& path = "./data/")
    { 
        _rpc_server = std::make_shared<brpc::Server>();
        FileServiceImpl* file_service = new FileServiceImpl(path); 
        bool ret = _rpc_server->AddService(file_service,
                                           brpc::ServiceOwnership::SERVER_OWNS_SERVICE);

        if (ret == -1)
        {
            LOG_ERROR("添加rpc服务失败");
            abort();
        }
        // 启动服务器
        brpc::ServerOptions options;
        // 连接空闲超时时间，-1表示
        options.idle_timeout_sec = -1;
        // io线程数量
        options.num_threads = 1;
        ret = _rpc_server->Start(port, &options);
        if (ret == -1)
        {
            LOG_ERROR("服务启动失败");
            abort();
        }
    }

    FileServer::ptr build()
    {
        if (!_reg_client)
        {
            LOG_ERROR("没有初始化服务注册服务");
            abort();
        }

        if (!_rpc_server)
        {
            LOG_ERROR("没有初始化rpc服务");
            abort();
        }

        FileServer::ptr server = std::make_shared<FileServer>(_reg_client, _rpc_server);
        return server;
    }

private:
    Registery::ptr _reg_client;
    std::shared_ptr<brpc::Server> _rpc_server;
};
